summaryrefslogtreecommitdiff
path: root/src-migrate/pages/shop/product/[slug].tsx
blob: 8d6558b1e57c912afe2d1cbad0ea1d7a511a9627 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { GetServerSideProps, NextPage } from 'next';
import React, { useEffect } from 'react';
import dynamic from 'next/dynamic';
import cookie from 'cookie';

import { getProductById } from '~/services/product';
import { createSlug, getIdFromSlug } from '~/libs/slug'; // <-- tambahin createSlug
import { IProductDetail } from '~/types/product';

import { Seo } from '~/components/seo';
import { useRouter } from 'next/router';
import { useProductContext } from '@/contexts/ProductContext';

const BasicLayout = dynamic(
  () => import('@/core/components/layouts/BasicLayout'),
  { ssr: false }
);
const ProductDetail = dynamic(() => import('~/modules/product-detail'), {
  ssr: false,
});

type PageProps = {
  product: IProductDetail;
  canonicalPath: string;
};

export const getServerSideProps: GetServerSideProps<PageProps> = async (
  context
) => {
  const { slug } = context.query;

  // ambil cookie pricelist tier
  const cookieString = context.req.headers.cookie;
  const cookies = cookieString ? cookie.parse(cookieString) : {};
  const auth = cookies?.auth ? JSON.parse(cookies.auth) : {};
  const tier = auth?.pricelist || '';

  // ambil ID produk dari slug URL
  const productId = getIdFromSlug(slug as string);

  // fetch data produk dari backend lo
  const product = await getProductById(productId, tier);

  // hard guard: produk gak ada -> 404
  if (!product) return { notFound: true };

  // guard: gak ada varian harga valid -> 404
  const hasValidVariant =
    Array.isArray(product.variants) &&
    product.variants.some((v) => (v?.price?.price ?? 0) > 0);

  // if (!hasValidVariant) return { notFound: true };

  // bikin canonical path yang BERSIH dan KONSISTEN dari data produk,
  // bukan dari URL request user (jadi gak ikut ?utm_source, ?ref=, dsb)
  const canonicalPath = createSlug(
    '/shop/product/', // ganti ini sesuai prefix route produk lo yang SEBENARNYA
    product?.name || '',
    product?.id,
    false // false = jangan include host di sini
  );

  return {
    props: {
      product,
      canonicalPath,
    },
  };
};

const ProductDetailPage: NextPage<PageProps> = ({ product, canonicalPath }) => {
  const router = useRouter();
  const { setProduct } = useProductContext();

  // taruh product di context global lo
  useEffect(() => {
    if (product) setProduct(product);
  }, [product, setProduct]);

  // rapihin origin biar gak double slash
  const origin = (process.env.NEXT_PUBLIC_SELF_HOST || '').replace(/\/+$/, '');
  const pathClean = canonicalPath.startsWith('/')
    ? canonicalPath
    : `/${canonicalPath}`;
  const url = origin + pathClean;

  // optional: pastiin OG image absolute URL
  const ogImageUrl = product?.image?.startsWith('http')
    ? product.image
    : origin + product?.image;

  return (
    <BasicLayout>
      <Seo
        title={`${product.name} - Indoteknik.com`}
        description='Temukan pilihan produk B2B Industri &amp; Alat Teknik untuk Perusahaan, UMKM &amp; Pemerintah dengan lengkap, mudah dan transparan.'
        canonical={url} // <- ini diprioritaskan sama komponen Seo
        openGraph={{
          url,
          images: [
            {
              url: ogImageUrl,
              width: 800,
              height: 800,
              alt: product?.name,
            },
          ],
          type: 'product',
        }}
        additionalMetaTags={[
          {
            name: 'keywords',
            content: `${product?.name}, Harga ${product?.name}, Beli ${product?.name}, Spesifikasi ${product?.name}`,
          },
        ]}
      />

      <div className='md:container pt-4 md:pt-6'>
        <ProductDetail product={product} />
      </div>
    </BasicLayout>
  );
};

export default ProductDetailPage;